package com.chalmers.foa.gui;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.Iterator;
import java.util.List;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import com.chalmers.foa.gamehandlers.impl.CollisionHandler;
import com.chalmers.foa.gamehandlers.impl.InputHandler;
import com.chalmers.foa.gamemodel.gameobjects.GameObjectBitmapAdapter;
import com.chalmers.foa.gamemodel.gameobjects.IGameObject;
import com.chalmers.foa.gamemodel.gameobjects.effects.ParticleAdapter;
import com.chalmers.foa.gamemodel.gameobjects.effects.impl.Particle;
import com.chalmers.foa.gamemodel.gameobjects.other.impl.Enemy;
import com.chalmers.foa.gamemodel.level.ILevel;

public class GameView extends SurfaceView implements SurfaceHolder.Callback {

	private static final int DEFAULT_SCREEN_WIDTH = 480;
	private static final int DEFAULT_SCREEN_HEIGHT = 320;

	public enum SurfaceState {
		Not_Created, Created, Destroyed;
	}

	// ILevel level;
	Paint mPaint; // The paint for the drawing cursor and the text
	SurfaceState surfaceState = SurfaceState.Not_Created;
	PropertyChangeSupport pcs;
	IGameObject[] gameObjects;
	List<Particle> particles;
	String introText;
	boolean sizeSet;
	boolean showLevelText;

	public GameView(Context context) {
		super(context);
		getHolder().addCallback(this); // Gives controll to the underlying
		// surface
		init(); // Initializes variables and states
	}

	public GameView(Context context, AttributeSet attrs) {
		super(context, attrs);
		getHolder().addCallback(this);
		init();
	}

	public GameView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		getHolder().addCallback(this);
		init();
	}

	/**
	 * Initializes the variables
	 */
	private void init() {
		mPaint = new Paint();
		mPaint.setTextSize(24);
		pcs = new PropertyChangeSupport(this);
	}

	public void setLevel(ILevel _level) {
		// level = _level;
		particles = _level.getParticles();
		gameObjects = _level.getGameObjectsAsArray();
		introText = _level.getLevelIntro();
		sizeSet = false;
		showLevelText = true;
	}

	public void setLevelText(boolean _levelText) {
		showLevelText = _levelText;
	}

	public boolean showLevelText() {
		return showLevelText;
	}

	public void setScreenSize() {
		// Detects the size of the screen
		float density = getContext().getResources().getDisplayMetrics().density;
		// If density equals 0 the screen size is the default screen size
		if (density != 0) {
			// If the screen size is not scalable to the default screen size we
			// add an extra start position. (Start x!=0/y!=0)
			Point startPos = new Point(
					(int) ((getWidth() - DEFAULT_SCREEN_WIDTH * density) / 2),
					(int) ((getHeight() - DEFAULT_SCREEN_HEIGHT * density) / 2));
			Log.v("Pos", startPos + "");
			if (startPos.x >= 0 && startPos.y >= 0) {
				for (IGameObject object : gameObjects) { // Changes the
					// positions of all
					// the game objects
					// to the new size
					object.setPosition(new Point(
							(int) (object.getPosition().x * density)
									+ startPos.x,
							(int) (object.getPosition().y * density)
									+ startPos.y));
					if (object instanceof Enemy)
						((Enemy) object).setVelocity(density);
				}
				sizeSet = true;
				// Updates the collision handler to the new screen size, and
				// possible new start positions
				CollisionHandler.getInstance().setScreenSize(
						new Point((int) (DEFAULT_SCREEN_WIDTH * density),
								(int) (DEFAULT_SCREEN_HEIGHT * density)),
						startPos);
				// Sets the speed multiplier ( Higher resolution => Player moves
				// more pixels )
				InputHandler.getInstance().setSpeedMultiplier(density);
			}
		}
	}

	/**
	 * Clears the previus canvas and draws the new one
	 * 
	 * @param canvas
	 *            The cavas is where everything on the screen is drawn
	 */
	@Override
	public void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		if (!surfaceState.equals(SurfaceState.Created) || canvas == null)
			return;
		mPaint.setColor(Color.BLACK);
		canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
		if (!sizeSet) {
			setScreenSize();
		}
		//Draw game objects
		if (gameObjects.length > 0)
			drawGameObjects(canvas);
		// Draw particles
		if (particles.size() > 0)
			drawGameParticles(canvas);
		// Draw the intro level text
		if (showLevelText)
			drawLevelText(canvas);
	}
	
	public void drawGameObjects(Canvas canvas){
		for (IGameObject object : gameObjects) {
			if (object.isAlive())
				canvas.drawBitmap(((GameObjectBitmapAdapter) object)
						.getBitmap(), object.getPosition().x, object
						.getPosition().y, null);
		}
	}
	public void drawGameParticles(Canvas canvas){
		Iterator<Particle> it = particles.iterator();
		while (it.hasNext()) {
			synchronized (it) {
				Particle particle = (Particle) it.next();
				mPaint.setColor(particle.getColor());
				canvas.drawRect(((ParticleAdapter) particle).getRect(),
						mPaint);
			}
		}
	}
	public void drawLevelText(Canvas canvas){
		mPaint.setColor(Color.WHITE);
		mPaint.setStyle(Paint.Style.FILL);
		mPaint.setAntiAlias(true);
		mPaint.setTextSize(30);
		mPaint.setTextAlign(Paint.Align.CENTER);
		canvas.drawText(introText, getWidth() / (float)2, getHeight() / (float)2, mPaint);

	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		// TODO Auto-generated method stub
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		surfaceState = SurfaceState.Created;
		pcs.firePropertyChange(new PropertyChangeEvent(this, "StartThread",
				null, null));
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		surfaceState = SurfaceState.Destroyed;
	}

	public SurfaceState getState() {
		return surfaceState;
	}

	public void setState(SurfaceState _state) {
		surfaceState = _state;
	}

	public void addPropertyChangeListener(PropertyChangeListener listener) {
		this.pcs.addPropertyChangeListener(listener);
	}
}
